package com.business.lgh.naocs.naming.core.pojo;

import com.business.lgh.nacos.api.naming.pojo.Cluster;
import com.business.lgh.nacos.api.naming.pojo.Instance;
import com.business.lgh.nacos.api.naming.pojo.Service;
import com.business.lgh.nacos.api.naming.utils.NamingUtils;
import com.business.lgh.naocs.naming.consistency.KeyBuilder;
import com.business.lgh.naocs.naming.consistency.Record;
import com.business.lgh.naocs.naming.consistency.RecordListener;
import com.business.lgh.naocs.naming.constant.UtilsAndCommons;
import com.business.lgh.naocs.naming.health.HealthPools;
import com.business.lgh.naocs.naming.health.HealthTask;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lgh
 * @version V1.0
 * @Package com.business.lgh.naocs.naming.core.pojo
 * @date 2020/6/24 5:09 下午
 */
@Component
@Data
public class ServiceWrapper extends Service implements RecordListener, Record {

    private volatile long lastModifyTime = System.currentTimeMillis();


    /**
     * 存放集群的集合
     */
    private Map<String, ClusterWrapper> clusterMap = new ConcurrentHashMap<>();


    @Override
    public String getCheckSum() {
        return null;
    }

    @Override
    public void onChange(String key, Record value) {
        Instances instances = (Instances) value;
        updateIps(instances.getInstances(), KeyBuilder.matchEphemeralInstanceListKey(key));
    }

    private void updateIps(List<InstanceWrapper> instances, boolean ephemeral) {

        //① 先构建service 各个子集群的关系的临时集合，实际就是clusterTmp集合
        Map<String, List<InstanceWrapper>> clusterTmp = new HashMap<>();
        clusterMap.keySet().forEach(k -> {
            clusterTmp.put(k, new ArrayList<>());
        });

        //② 再把各个节点分门别类的重新放到临时结合里，
        for (InstanceWrapper instance : instances) {
            if (instance == null)
                continue;

            //如果实例没有集群名字，则设置默认的
            if (StringUtils.isEmpty(instance.getClusterName())) {
                instance.setClusterName(UtilsAndCommons.DEFAULT_CLUSTER_NAME);
            }

            if (!clusterMap.containsKey(instance.getClusterName())) {
                ClusterWrapper cluster = new ClusterWrapper(instance.getClusterName(), this);
                cluster.init();
                getClusterMap().put(instance.getClusterName(), cluster);
            }
            //拿到集群对应的集合
            List<InstanceWrapper> clusterIps = clusterTmp.get(instance.getClusterName());
            if (clusterIps == null) {
                clusterIps = new LinkedList<>();
                clusterTmp.put(instance.getClusterName(), clusterIps);
            }
            clusterIps.add(instance);
        }

        //开始遍历新的集合，更新旧的cluster相关信息
        for (Map.Entry<String, List<InstanceWrapper>> entry : clusterTmp.entrySet()) {
            clusterMap.get(entry.getKey()).updateIps(entry.getValue(),ephemeral);
        }

        setLastModifyTime(System.currentTimeMillis());
    }


    /**
     * 重新计算校验和
     */
    public void recalculateChecksum() {

    }

    public void validate() {
    }

    public void init() {
        //开启心跳监控检查
        HealthPools.submit(new HealthTask(this));
    }

    /**
     * 拿到该服务的所有节点
     *
     * @param ephemeral
     * @return
     */
    public List<InstanceWrapper> allIps(boolean ephemeral) {
        List<InstanceWrapper> allIPs = new ArrayList<>();
        clusterMap.forEach((k, v) -> {
            allIPs.addAll(v.allIps(ephemeral));
        });
        return allIPs;
    }

    //获取service所有实例
    public List<InstanceWrapper> allIPs(boolean isEphemeral) {
        List<InstanceWrapper> allIPs;
        allIPs=clusterMap.values().stream()
                .flatMap(v->v.allIPs(isEphemeral).stream()).collect(Collectors.toList());
        return allIPs;
    }

    //获取service所有实例
    public List<InstanceWrapper> allIPs() {
        List<InstanceWrapper> allIPs;
        allIPs=clusterMap.values().stream()
                .flatMap(v->v.allIPs().stream()).collect(Collectors.toList());
        return allIPs;
    }

    public int healthyInstanceCount() {
        List<InstanceWrapper> list=allIPs();
        int count=0;
        if (list!=null){
            count = (int) list.stream().filter(x -> x.isHealthy() == true).count();
        }
        return count;
    }
}
